package com.lookme.lmtool.cracker;

import cn.hutool.core.annotation.AnnotationUtil;
import com.jfoenix.controls.JFXColorPicker;
import com.jfoenix.controls.JFXSlider;
import com.lookme.core.javafx.control.DoubleSpinner;
import com.lookme.lmtool.cracker.annotation.ParamAnnotation;
import com.lookme.lmtool.utils.ImageUtils;
import com.lookme.lmtool.utils.ReflectUtils;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.util.Callback;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class CrackerEditor {

    public static List<Field> getHasParamFieldList(ICracker cracker){
        List<Field> list=new ArrayList<>();
        Field[] fields= cracker.getClass().getDeclaredFields();
        for(Field field:fields){
            ParamAnnotation annotation= AnnotationUtil.getAnnotation(field,ParamAnnotation.class);
            if(annotation!=null){
                list.add(field);
            }
        }
        return list;
    }


    public static void createParamEditor(Pane parentPane, ICracker cracker, Callback<ICracker,Void> callback){
        parentPane.getChildren().clear();

        List<Field> fields=getHasParamFieldList(cracker);

        if(fields.size()>0) {
            for (Field field : fields) {
                try {
                    field.setAccessible(true);
                    Object objValue=field.get(cracker);
                    String value="";
                    if(objValue!=null){
                        value=objValue.toString();
                    }

                    ParamAnnotation annotation = field.getAnnotation(ParamAnnotation.class);
                    HBox box = new HBox(5);

                    box.setAlignment(Pos.CENTER_LEFT);
                    box.setPrefHeight(30);
                    Label label = new Label(annotation.name() + ":");
                    label.setTooltip(new Tooltip(annotation.desc()));
                    label.setAlignment(Pos.CENTER_RIGHT);
                    box.getChildren().add(label);
                    if (annotation.inputType() == ParamAnnotation.InputType.Text) {
                        TextField textField = new TextField("" + value);
                        textField.setPrefWidth(annotation.width());
                        HBox.setMargin(textField, new Insets(annotation.margin()[0], annotation.margin()[1], annotation.margin()[2], annotation.margin()[3]));
                        textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
                            @Override
                            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                                if (!newValue) {
                                    ReflectUtils.setFieldValue(cracker,field,textField.getText());
                                    callback.call(cracker);
                                }
                            }
                        });
                        textField.setOnKeyPressed((KeyEvent E) -> {
                            switch (E.getCode()) {
                                case ENTER:
                                    ReflectUtils.setFieldValue(cracker,field,textField.getText());
                                    E.consume();
                                    callback.call(cracker);
                                    break;
                            }
                        });
                        box.getChildren().add(textField);
                    } else if (annotation.inputType() == ParamAnnotation.InputType.Radio) {
                        ToggleGroup group = new ToggleGroup();
                        HBox hbox = new HBox();
                        hbox.setAlignment(Pos.CENTER);
                        HBox.setMargin(hbox, new Insets(annotation.margin()[0], annotation.margin()[1], annotation.margin()[2], annotation.margin()[3]));
                        for(int i=0;i<annotation.options().length;i+=2){
                            RadioButton radioButton = new RadioButton(annotation.options()[i]);
                            radioButton.setToggleGroup(group);
                            radioButton.setPrefWidth(annotation.width());
                            if (field.get(cracker)!=null&&field.get(cracker).toString().equals(annotation.options()[i+1])) {
                                radioButton.setSelected(true);
                            }
                            final int lasti=i;
                            radioButton.selectedProperty().addListener(new ChangeListener<Boolean>() {
                                @Override
                                public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                                    if (newValue) {
                                        ReflectUtils.setFieldValue(cracker,field,annotation.options()[lasti+1]);
                                        callback.call(cracker);
                                    }
                                }
                            });
                            hbox.getChildren().add(radioButton);
                        }
                        box.getChildren().add(hbox);
                    } else if (annotation.inputType() == ParamAnnotation.InputType.Combox) {
                        ComboBox<String> comboBox = new ComboBox<>();
                        comboBox.setPrefWidth(annotation.width());
                        HBox.setMargin(comboBox, new Insets(annotation.margin()[0], annotation.margin()[1], annotation.margin()[2], annotation.margin()[3]));
                        java.util.List<String> options = new ArrayList<>();
                        for(int i=0;i<annotation.options().length;i+=2) {
                            options.add(annotation.options()[i]);
                        }
                        comboBox.setItems(FXCollections.observableArrayList(options));
                        comboBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
                            @Override
                            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                                ReflectUtils.setFieldValue(cracker,field,annotation.options()[comboBox.getSelectionModel().getSelectedIndex()*2+1]);
                                callback.call(cracker);
                            }
                        });
                        box.getChildren().add(comboBox);
                    } else if (annotation.inputType() == ParamAnnotation.InputType.Spinner) {
                        DoubleSpinner spinner = new DoubleSpinner( annotation.min(), annotation.max(), annotation.initialValue(),annotation.amountToStepBy());
                        spinner.setPrefWidth(annotation.width());
                        try {
                            spinner.setValue(Double.parseDouble(value));
                        }catch(Exception e){

                        }
                        spinner.setEditable(true);
                        HBox.setMargin(spinner, new Insets(annotation.margin()[0], annotation.margin()[1], annotation.margin()[2], annotation.margin()[3]));
                        spinner.getEditor().focusedProperty().addListener(new ChangeListener<Boolean>() {
                            @Override
                            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                                if (!newValue) {

                                    ReflectUtils.setFieldValue(cracker,field,spinner.getEditor().getText());
                                    callback.call(cracker);
                                }
                            }
                        });
                        spinner.getEditor().setOnKeyPressed((KeyEvent E) -> {
                            switch (E.getCode()) {
                                case ENTER:
                                    ReflectUtils.setFieldValue(cracker,field,spinner.getEditor().getText());
                                    E.consume();
                                    callback.call(cracker);
                                    break;
                            }
                        });
                        spinner.valueProperty().addListener(new ChangeListener<Double>() {
                            @Override
                            public void changed(ObservableValue<? extends Double> observable, Double oldValue, Double newValue) {
                                ReflectUtils.setFieldValue(cracker,field,""+newValue);
                                callback.call(cracker);
                            }
                        });
                        box.getChildren().add(spinner);
                    }  else if (annotation.inputType() == ParamAnnotation.InputType.Slider) {
                        JFXSlider slider = new JFXSlider( annotation.min(), annotation.max(), Double.parseDouble(value));
                        slider.setPrefWidth(annotation.width());
                        slider.setBlockIncrement(annotation.blockIncrement());
                        slider.setShowTickLabels(true);
                        slider.setShowTickMarks(true);
                        slider.setMajorTickUnit(annotation.majorTickUnit());
                        slider.setMinorTickCount(annotation.minorTickCount());
                        slider.setValue(Double.parseDouble(value));
                        HBox.setMargin(slider, new Insets(annotation.margin()[0], annotation.margin()[1], annotation.margin()[2], annotation.margin()[3]));
                        slider.valueProperty().addListener((observable, oldValue, newValue) -> {
                            ReflectUtils.setFieldValue(cracker,field,""+newValue);
                            callback.call(cracker);
                        });
                        box.getChildren().add(slider);
                    } else if (annotation.inputType() == ParamAnnotation.InputType.ColorPicker) {
                        ColorPicker colorPicker = new ColorPicker();
                        colorPicker.setPrefWidth(annotation.width());
                        if (StringUtils.isNotEmpty(value.toString())) {
                            try{
                                colorPicker.setValue(Color.valueOf(value));}
                            catch(Exception e){

                            }
                        }
                        HBox.setMargin(colorPicker, new Insets(annotation.margin()[0], annotation.margin()[1], annotation.margin()[2], annotation.margin()[3]));
                        colorPicker.valueProperty().addListener((observable, oldValue, newValue) -> {
                            ReflectUtils.setFieldValue(cracker,field,""+ ImageUtils.fxColorToInt(newValue));
                            callback.call(cracker);
                        });
                        box.getChildren().add(colorPicker);
                    }
                    parentPane.getChildren().add(box);
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }else{
            Label label=new Label("当前滤镜无配置参数");
            label.setAlignment(Pos.CENTER);
            label.setPrefWidth(parentPane.getPrefWidth()-20);
            parentPane.getChildren().add(label);
        }
    }
}
